package sany.iec.service;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import sany.iec.config.GlobalVariable;
import sany.iec.config.ParameterConfig;
import sany.iec.entity.DataEntity;
import sany.iec.entity.ServerEntity;
import sany.iec.enums.*;
import sany.iec.utils.ExcelUtil;
import sany.iec.utils.FormulaCalculationUtil;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.io.IOException;
import java.util.*;

/**
 * @Author 托马斯
 * @Date 2025/7/6 0:13
 * @Description InitService
 */
@Service
@Slf4j
public class InitService {

    @Resource
    private ParameterConfig parameterConfig;

    @Resource
    private ModbusServerService modbusServerService;

    @Resource
    private ServerService serverService;

    private Set<Integer> PORT_SET = new HashSet<>();

    @PostConstruct
    public void init() throws InterruptedException {
        // 1. 读取excel数据
        Assert.isTrue(ExcelUtil.existExcel(parameterConfig.getExcelAddress()), String.format("Excel文件不存在: %s", parameterConfig.getExcelAddress()));
        Map<String, List<List<String>>> excelData = ExcelUtil.readExcel(parameterConfig.getExcelAddress(), 0, 0);
        log.info("Excel存在的文件名：{}", excelData.keySet());
        // 2. 查看是否有配置的参数表
        Assert.isTrue(excelData.containsKey(parameterConfig.getParameterTableName()), String.format("不存在配置的数据表: %s", parameterConfig.getParameterTableName()));
        // 3. 将参数配置表加载进入缓存
        Assert.isTrue(loadParameterConfig(excelData.get(parameterConfig.getParameterTableName())), "加载参数配置表入缓存出错。");
        // 4. 将其他配置数据进行组装为实体
        excelData.forEach((k, v) -> {
            Assert.isTrue(loadServerDataEntity(k, v), String.format("加载服务配置信息入缓存出错,table: %s", k));
        });
        // 5. 开启服务
        GlobalVariable.SERVER_LIST.forEach(server -> {
            try {
                serverService.startServer(server);
                log.info("table: {}, 协议: {}, 端口: {}, 服务启动成功。", server.getTableName(), server.getServerType(), server.getPort());
            } catch (IOException e) {
                log.error("开启服务失败，table: {} port: {} 协议: {}", server.getTableName(), server.getPort(), server.getServerType(), e);
            }
        });

        log.info("正在初始化数据....  请等待3秒。");
        Thread.sleep(3000);

        // 6. 完成数据初始化
        // ----------  modbus数据写入对应的类型  ---------------
        for (ServerEntity serverEntity : GlobalVariable.SERVER_LIST) {
            if (serverEntity.getServerType().equals(ServerType.IEC104)) {
                // ----------  IEC104数据写入缓存  ------------------
                for (DataEntity listDatum : serverEntity.getListData()) {
                    GlobalVariable.GLOBAL_MAP.put(serverEntity.getPort() + ":" + listDatum.getKey(),
                            FormulaCalculationUtil.getFormulaResult(serverEntity.getTableName(), listDatum.getOriginInitValue()));
                }
            } else if (serverEntity.getServerType().equals(ServerType.MODBUS)) {
                // -----------  MODBUS数据写入对应的BasicProcessImage -------
                for (DataEntity listDatum : serverEntity.getListData()) {
                    if (listDatum.getModbusRegisterEnum().equals(ModbusRegisterEnum.COIL)) {
                        modbusServerService.writeCoil(serverEntity, listDatum,
                                FormulaCalculationUtil.getFormulaResult(serverEntity.getTableName(), listDatum.getOriginInitValue()) == 1.0f);
                    } else if (listDatum.getModbusRegisterEnum().equals(ModbusRegisterEnum.INPUT)) {
                        modbusServerService.writeInput(serverEntity, listDatum,
                                FormulaCalculationUtil.getFormulaResult(serverEntity.getTableName(), listDatum.getOriginInitValue()) == 1.0f);
                    } else if (listDatum.getModbusRegisterEnum().equals(ModbusRegisterEnum.HOLD_REGISTER)) {
                        modbusServerService.writeHoldRegister(serverEntity, listDatum,
                                FormulaCalculationUtil.getFormulaResult(serverEntity.getTableName(), listDatum.getOriginInitValue()));
                    } else if (listDatum.getModbusRegisterEnum().equals(ModbusRegisterEnum.INPUT_REGISTER)) {
                        modbusServerService.writeInputRegister(serverEntity, listDatum,
                                FormulaCalculationUtil.getFormulaResult(serverEntity.getTableName(), listDatum.getOriginInitValue()));
                    } else {
                        log.warn("未知数据，tableName: {}, data: {}", serverEntity.getTableName(), listDatum);
                    }
                }
            } else {
                log.warn("未知服务：{}", serverEntity.getTableName());
            }
            log.info("完成 {} 数据初始化设置。", serverEntity.getTableName());
        }

        // 7. svg容量如缓存
        for (ServerEntity serverEntity : GlobalVariable.SERVER_LIST) {
            if (serverEntity.getSvgCapacity() != null) {
                GlobalVariable.GLOBAL_MAP.put(serverEntity.getPort() + ":" + "SVG", serverEntity.getSvgCapacity());
            }
        }
    }

    /**
     * 加载服务信息进入缓存
     *
     * @param tableName : 表名
     * @param list      : 服务信息
     */
    private Boolean loadServerDataEntity(String tableName, List<List<String>> list) {
        if (tableName.toLowerCase().contains(parameterConfig.getParameterTableName().toLowerCase())) {
            // 参数表跳过加载
            return true;
        }
        if (!EnableEnum.Enabled.getFlag().equals(list.get(1).get(3))) {
            log.warn("{} 不进行启用", tableName);
            return true;
        }
        ServerEntity server;
        try {
            server = getServerEntity(tableName, list.get(1));
            if (server == null) {
                log.error("加载服务信息表出错: {}", tableName);
                return false;
            }
            server = getElementData(server, list);
        } catch (Exception e) {
            log.error("加载服务信息出错", e);
            return false;
        }
        log.info("加载服务信息表成功：{}，端口: {}, modbusID: {}, len: {}", tableName, server.getPort(), server.getModbusId(), server.getDataLength());
        GlobalVariable.SERVER_LIST.add(server);
        return true;
    }

    private ServerEntity getElementData(ServerEntity server, List<List<String>> list) {
        Set<String> setKey = new HashSet<>();
        if (!PORT_SET.add(server.getPort())) {
            Assert.isTrue(false, String.format("端口不可重复: %s, 重复端口: %s", server.getTableName(), server.getPort()));
        }
        for (int i = 3; i < list.size(); i++) {
            if (StringUtils.isBlank(list.get(i).get(0))) {
                break;
            }
            if (StringUtils.isBlank(list.get(i).get(7)) || !setKey.add(list.get(i).get(7))) {
                Assert.isTrue(false, String.format("key不可重复且必须填写: %s", server.getTableName()));
            }
            DataEntity build = DataEntity.builder()
                    .category(DataCategoryEnum.getDataCategoryEnum(list.get(i).get(0)))
                    .modbusRegisterEnum(ModbusRegisterEnum.getModbusRegisterEnum(list.get(i).get(1)))
                    .iec104DataTypeEnum(IEC104DataTypeEnum.getIEC104DataTypeEnum(list.get(i).get(2)))
                    .modbusDataTypeEnum(ModbusDataTypeEnum.getModbusDataTypeEnum(list.get(i).get(2)))
                    .iec104CommonAddress(getCommonAddress(list.get(i).get(3)))
                    .address(Integer.parseInt(list.get(i).get(4)))
                    .originInitValue(list.get(i).get(5).trim())
                    .deviation(Float.parseFloat(list.get(i).get(6)))
                    .key(list.get(i).get(7).trim())
                    .calculationFormula(list.get(i).get(8).trim())
                    .updateEnable(EnableEnum.getEnableEnum(list.get(i).get(9).trim()))
                    .build();
            Assert.notNull(build.getCategory(), String.format("必须填写数据类别: %s", server.getTableName()));
            if (StringUtils.isBlank(build.getKey())) {
                Assert.isTrue(false, String.format("必须填写key: %s", server.getTableName()));
            }
            if (server.getServerType().equals(ServerType.IEC104)) {
                // 如果是IEC104协议
                Assert.notNull(build.getIec104DataTypeEnum(), String.format("IEC104协议必须填写数据类型: %s", server.getTableName()));
                Assert.notNull(build.getIec104CommonAddress(), String.format("IEC104协议必须填写公共地址: %s", server.getTableName()));
            } else {
                // 如果是modbus协议
                Assert.notNull(build.getModbusRegisterEnum(), String.format("MODBUS协议必须填写寄存器: %s", server.getTableName()));
                Assert.notNull(build.getModbusDataTypeEnum(), String.format("MODBUS协议必须填写数据类型: %s", server.getTableName()));
            }
            server.setDataLength(Math.max(server.getDataLength(), build.getAddress() + 10));
            server.getListData().add(build);
        }
        return server;
    }

    /**
     * 得到公共地址
     *
     * @param commonAddress : 公共地址字符串
     */
    private Integer getCommonAddress(String commonAddress) {
        try {
            Float v = Float.parseFloat(commonAddress);
            return v.intValue();
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * 加载服务信息表
     *
     * @param tableName : 表名字
     * @param list      : 服务信息行数据
     * @return
     */
    private ServerEntity getServerEntity(String tableName, List<String> list) {
        // 1. 检查服务名称是否正确
        ServerType serverType = ServerType.getServerType(list.get(0));
        if (serverType == null) {
            log.info("{} 服务名称配置错误", tableName);
            return null;
        }
        int modbusId = Integer.MAX_VALUE;
        if (StringUtils.isNotBlank(list.get(2))) {
            modbusId = Integer.parseInt(list.get(2));
        }
        float SVGInstall = GlobalVariable.SVG_INSTALL_DEFAULT;
        if (StringUtils.isNotBlank(list.get(4))) {
            SVGInstall = Float.parseFloat(list.get(4));
        }
        float EMSInstall = 0.0f;
        if (StringUtils.isNotBlank(list.get(5))) {
            EMSInstall = Float.parseFloat(list.get(5));
        }
        log.warn("EMSInstall: {}", EMSInstall);
        ServerEntity server = ServerEntity.builder()
                .tableName(tableName)
                .serverType(serverType)
                .port(Integer.parseInt(list.get(1)))
                .modbusId(modbusId)
                .enable(EnableEnum.Enabled)
                .svgCapacity(SVGInstall)
                .InstalledCapacity(EMSInstall)
                .dataLength(0)
                .listData(new ArrayList<>())
                .build();
        return server;
    }

    /**
     * 将参数表数据入缓存
     *
     * @param list : 参数表数据
     */
    private Boolean loadParameterConfig(List<List<String>> list) {
        // 过滤第一行的标题
        for (int i = 1; i < list.size(); i++) {
            try {
                Float v = Float.parseFloat(list.get(i).get(1).trim());
                GlobalVariable.GLOBAL_MAP.put(list.get(i).get(0).trim(), v);
            } catch (Exception e) {
                log.error(e.getMessage());
                return false;
            }
        }
        log.info("加载参数表成功：{}", parameterConfig.getParameterTableName());
        return true;
    }

}
